﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;

namespace Skybot.Logs.Broken
{
    /// <summary>
    /// 日志写入基础类
    /// </summary>
    public class LogWriteHelper
    {
        /// <summary>
        /// 运行目录下创建的基本目标
        /// </summary>
        private string baseLogPath = "logs";

        /// <summary>
        /// 运行目录下创建的基本目标
        /// </summary>
        public string BaseLogPath
        {
            get { return baseLogPath; }
            set { baseLogPath = value; }
        }

        public bool Write(string terminalCode, string data)
        {
            try
            {
                var path = LogPath(terminalCode);
                using (var fso = File.AppendText(path))
                {
                    fso.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " : " + data);
                    fso.Close();
                }
                return true;
            }
            catch
            {
                return false;

            }
        }

        public void WriteExecption(string content)
        {
            try
            {
                var path = LogPath("Pubic");
                using (var fso = File.AppendText(path))
                {
                    fso.WriteLine(DateTime.Now.ToString(CultureInfo.InvariantCulture) + " 异常数据描述:" + content);
                    fso.Close();
                }


            }
            catch
            {
            }
        }



        public string LogPath(string terminal, string tag = null)
        {
            CreatePath(terminal);
            CreateText(terminal);
            var date = DateTime.Now.ToString("yyyy-MM-dd");
            if (tag == null)
            {
                return AppDomain.CurrentDomain.BaseDirectory + @"\" + baseLogPath + @"\" + terminal + @"\" + date + ".log";

            }
            else
            {
                return AppDomain.CurrentDomain.BaseDirectory + @"\" + baseLogPath + @"\" + terminal + @"\" + date + tag + ".log";

            }

        }


        private void CreatePath(string terminal)
        {
            var path = AppDomain.CurrentDomain.BaseDirectory + @"\" + baseLogPath + @"\";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            path = AppDomain.CurrentDomain.BaseDirectory + @"\" + baseLogPath + @"\" + terminal;
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }

        private void CreateText(string terminalCode)
        {
            var date = DateTime.Now.ToString("yyyy-MM-dd");
            var path = AppDomain.CurrentDomain.BaseDirectory + @"\" + baseLogPath + @"\" + terminalCode + @"\";
            if (File.Exists(path + date + ".log"))
            {
                return;
            }
            //删除90天以前的数据
#if delold
            var oldDate = DateTime.Now.AddDays(-90).ToString("yyyy-MM-dd");
            if (File.Exists(path + oldDate + ".log"))
            {
                File.Delete(path + oldDate + ".log");
            }
#endif
            //try
            //{
            //创建文件
            using (var fs = File.CreateText(path + date + ".log"))
            {
                fs.Close();
            }
            //}
            //catch (IOException ex)
            //{
            //    Console.WriteLine(ex);
            //}
        }
    }

    /// <summary>
    /// 第二种写日志的方法
    /// </summary>
    public class ForwardWriteLog
    {

        /// <summary>
        /// 初始化日志写入帮肋类
        /// </summary>
        internal LogWriteHelper logHelper = null;
        /// <summary>
        /// 创建新的日志写入类
        /// </summary>
        /// <param name="basePath"></param>
        public ForwardWriteLog(string basePath = "logs")
        {
            logHelper = new LogWriteHelper() { BaseLogPath = basePath };
#if 调试
     //多效创建测试
            string path = AppDomain.CurrentDomain.BaseDirectory + "/" + DateTime.Now.Day + ".txt";
            System.Diagnostics.StackTrace stack = new System.Diagnostics.StackTrace(System.Threading.Thread.CurrentThread, true);

           using(var fil= File.AppendText(path))
           {
               fil.WriteLine(); fil.WriteLine(); fil.WriteLine();
               fil.WriteLine();
               fil.WriteLine("目录:" + basePath);
               fil.WriteLine(); 
               fil.WriteLine(stack.ToString());
               fil.Close();
           }
       
#endif

        }


        /// <summary>
        /// 写日志字典:终端号,时间
        /// </summary>
        internal ConcurrentDictionary<string, WriteState> dic = new ConcurrentDictionary<string, WriteState>();

        /// <summary>
        /// 上次检查超时时间
        /// </summary>
        protected DateTime LastCheckTime = DateTime.Now;
        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="terminalCode">终端编号</param>
        /// <param name="data"></param>
        public virtual void Write(uint terminalCode, string data)
        {
            Write(terminalCode + string.Empty, data);
        }

        /// <summary>
        /// 写日志
        /// </summary>
        /// <param name="terminalCode">终端编号</param>
        /// <param name="data"></param>
        public virtual void Write(string terminalCode, string data)
        {
            string key = terminalCode + "," + DateTime.Now.ToString("yyyy-MM-dd");
            //查找内存中已经存在的状态数据
            WriteState state = null;
            dic.TryGetValue(key, out state);
            if (state == null)
            {
                #region 首次添加
                lock (dic)
                {
                    state = new WriteState();
                    if (dic.TryAdd(key, state))
                    {
                        state.TerminalCode = terminalCode;
                        state.Key = key;
                        state.Path = logHelper.LogPath(terminalCode.ToString(CultureInfo.InvariantCulture));
                    }
                    else
                    {
                        var obj = dic[key];
                        if (obj != null)
                        {
                            state = obj;
                        }
                    }
                }
                try
                {
                    lock (dic)
                    {
                        state.FileStream = File.AppendText(state.Path);
                    }
                }
                catch
                {

                }
                //下面代码不写入
                //fso.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " : " + data);
                //fso.Close();
                //fso.Dispose();
                #endregion

            }
            try
            {
                string writeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " : " + data;
                //将出错的内容写入到错误数据中
                if (state.FileStream == null)
                {
                    if (logHelper.Write(terminalCode, data))
                    {
                        try
                        {
                            state.FileStream = File.AppendText(state.Path);
                        }
                        catch
                        {

                        }
                    }
                    else
                    {
                        state.Writes.Add(writeStr);
                    }
                    return;
                }
                else
                {
                    if (state.Writes.Count > 0)
                    {
                        foreach (var item in state.Writes)
                        {
                            //开始写入数据
                            state.FileStream.WriteLine(item);
                        }
                        state.Writes.Clear();
                    }
                }

                //开始写入数据
                state.FileStream.WriteLine(writeStr);
                state.FileStream.Flush();
                state.LastWriteTime = DateTime.Now;
                //如果超过指定时间则
                if (LastCheckTime.AddMinutes(2) < DateTime.Now)
                {
                    CheckWriteTimeOut();
                }
            }
            catch (Exception)
            {
                Delete(key);
            }

        }

        /// <summary>
        /// 删除指定终端编号,数据
        /// </summary>
        /// <param name="key">终端编号</param>
        protected void Delete(string key)
        {
            WriteState delobj = null;
            //删除对像
            dic.TryRemove(key, out delobj);
            if (delobj == null)
            {
                return;
            }
            try
            {
                delobj.FileStream.Close();
                delobj.FileStream.Dispose();
            }
            catch
            {

            }
        }


        /// <summary>
        /// 写入时间超时
        /// </summary>
        protected void CheckWriteTimeOut()
        {
            if (LastCheckTime.AddMinutes(2) > DateTime.Now)
            {
                return;
            }
            //设置当前时间
            LastCheckTime = DateTime.Now;
            foreach (var item in dic.Values.ToArray())
            {
                //已经有5分钟没有写入数据了
                if (item.LastWriteTime.AddMinutes(5) <= DateTime.Now)
                {
                    //从队列中移除数据
                    Delete(item.Key);
                }
            }
        }


        /// <summary>
        /// 状态数据保存
        /// </summary>
        internal class WriteState
        {
            private List<string> writes = new List<string>();
            public List<string> Writes
            {
                get { return writes; }
            }
            /// <summary>
            /// 数据key
            /// </summary>
            public string Key { get; set; }

            /// <summary>
            /// 终端编号
            /// </summary>
            public string TerminalCode { get; set; }

            /// <summary>
            /// 路径
            /// </summary>
            public string Path { get; set; }

            /// <summary>
            /// 文件流对像
            /// </summary>
            public StreamWriter FileStream { get; set; }

            /// <summary>
            /// 最后写入时间
            /// </summary>
            public DateTime LastWriteTime { get; set; }


        }
    }

    /// <summary>
    /// 发送Send数据
    /// </summary>
    public class ForwardWriteSendLog : ForwardWriteLog
    {
        /// <summary>
        /// 创建新的日志写入类
        /// </summary>
        /// <param name="basePath"></param>
        public ForwardWriteSendLog(string basePath = "logs")
            : base(basePath)
        {

        }

        /// <summary>
        /// 写入发送内容
        /// </summary>
        /// <param name="terminalCode"></param>
        /// <param name="data"></param>
        public override void Write(uint terminalCode, string data)
        {
            Write(terminalCode + string.Empty, data);
        }

        /// <summary>
        /// 写入发送文件
        /// </summary>
        /// <param name="terminalCode"></param>
        /// <param name="data"></param>
        public override void Write(string terminalCode, string data)
        {
            string key = terminalCode + "," + DateTime.Now.ToString("yyyy-MM-dd");
            //查找内存中已经存在的状态数据
            WriteState state = null;
            dic.TryGetValue(key, out state);
            if (state == null)
            {
                #region 首次添加
                lock (dic)
                {
                    state = new WriteState();
                    if (dic.TryAdd(key, state))
                    {
                        state.TerminalCode = terminalCode;
                        state.Key = key;
                        state.Path = logHelper.LogPath(terminalCode.ToString(CultureInfo.InvariantCulture), "Send");
                    }
                    else
                    {
                        var obj = dic[key];
                        if (obj != null)
                        {
                            state = obj;
                        }
                    }
                }
                try
                {
                    lock (dic)
                    {
                        state.FileStream = File.AppendText(state.Path);
                    }
                }
                catch
                {

                }
                //下面代码不写入
                //fso.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " : " + data);
                //fso.Close();
                //fso.Dispose();
                #endregion

            }
            try
            {
                string writeStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " : " + data;
                //将出错的内容写入到错误数据中
                if (state.FileStream == null)
                {
                    if (logHelper.Write(terminalCode, data))
                    {
                        try
                        {
                            state.FileStream = File.AppendText(state.Path);
                        }
                        catch
                        {

                        }
                    }
                    else
                    {
                        state.Writes.Add(writeStr);
                    }
                    return;
                }
                else
                {
                    if (state.Writes.Count > 0)
                    {
                        foreach (var item in state.Writes)
                        {
                            //开始写入数据
                            state.FileStream.WriteLine(item);
                        }
                        state.Writes.Clear();
                    }
                }

                //开始写入数据
                state.FileStream.WriteLine(writeStr);
                state.FileStream.Flush();
                state.LastWriteTime = DateTime.Now;
                //如果超过指定时间则
                if (LastCheckTime.AddMinutes(2) < DateTime.Now)
                {
                    CheckWriteTimeOut();
                }
            }
            catch (Exception)
            {
                Delete(key);
            }
        }
    }

    /// <summary>
    /// 日志管理类,防止多次创建引起的,
    /// 日志文件句柄冲突,造成无法写入
    /// </summary>
    public class ForwardLogManager
    {
        /// <summary>
        /// logs目录日志文件写入
        /// </summary>
        private static readonly ForwardWriteLog _LogsWrite = new ForwardWriteLog();

        /// <summary>
        /// logs目录,Send文件写入
        /// </summary>
        private static readonly ForwardWriteSendLog _LogsSendWrite = new ForwardWriteSendLog();

        /// <summary>
        /// 目标节点目录写入
        /// </summary>
        private static readonly ConcurrentDictionary<string, ForwardWriteLog> targetWrite = new ConcurrentDictionary<string, ForwardWriteLog>();

        /// <summary>
        /// 目标节点目录写入
        /// </summary>
        private static readonly ConcurrentDictionary<string, ForwardWriteSendLog> targetSendWrite = new ConcurrentDictionary<string, ForwardWriteSendLog>();

        /// <summary>
        /// logs目录日志文件写入
        /// </summary>
        public static ForwardWriteLog LogsWrite
        {
            get { return _LogsWrite; }
        }

        /// <summary>
        /// logs目录,Send文件写入
        /// </summary>
        public static ForwardWriteSendLog LogsSendWrite
        {
            get { return _LogsSendWrite; }
        }

        /// <summary>
        /// 目标节点目录写入
        /// </summary>
        public static ConcurrentDictionary<string, ForwardWriteLog> TargetWrite
        {
            get { return targetWrite; }
        }

        /// <summary>
        /// 目标节点目录写入
        /// </summary>
        public static ConcurrentDictionary<string, ForwardWriteSendLog> TargetSendWrite
        {
            get { return targetSendWrite; }
        }

    }
}
